﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using InkFx.WinControl.Core;
using InkFx.WinControl.Design;
using InkFx.WinControl.Theme;
using InkFx.WinControl.Utils;
using DA = InkFx.WinControl.XIDEAlignment;
using DTG = InkFx.WinControl.XIDEGroup;
using DTGS = InkFx.WinControl.XIDEGroupState;
using DTGP = InkFx.WinControl.XIDEPage;

namespace InkFx.WinControl
{
    public partial class XIDEPanel
    {
        #region  逻 辑 函 数

        /// <summary>
        /// 如果 整个XIDEPanel 仅仅只有一个 中央未知的 Group, 则返回这个分组
        /// </summary>
        /// <returns></returns>
        public XIDEGroup FindOuterGroup()
        {
            var splits = this.GetListSplit();
            if (splits.Count >= 1) return null;

            var groups = this.GetListGroup();
            if (groups.Count == 1) return groups[0];
            var groups2 = groups.FindAll(x => (x.Bounds.Width >= 1 && x.Bounds.Height >= 1));
            if (groups2.Count >= 1) return groups2[0];

            return null;
        }
        /// <summary>
        /// 查找 XIDEPanel 最外围的那个 SplitControl
        /// </summary>
        /// <returns></returns>
        public XIDESplitControl FindOuterSplit()
        {
            var splits = this.GetListSplit();
            if (splits.Count == 1) return splits[0];

            var hash = GetHashSplitParent();
            var splits2 = splits.FindAll(x => !hash.ContainsKey(x));
            if (splits2.Count <= 0) return null;
            if (splits2.Count >= 2) 
                throw new Exception("查找到多个无父级 XIDESplitControl, 无法确定最外围的 XIDESplitControl");
            return splits2[0];
        }

        /// <summary>
        /// 查找指定 Group 所属的 Split面板
        /// </summary>
        /// <param name="group"></param>
        /// <returns></returns>
        public XIDESplitPanel FindParentPanel(XIDEGroup group)
        {
            if (group == null) return null;

            var splits = this.GetListSplit();
            foreach (var split in splits)
            {
                if (split.Panel1.Group == group) return split.Panel1;
                if (split.Panel2.Group == group) return split.Panel2;
            }

            return null;
        }
        /// <summary>
        /// 查找指定 SplitControl 所属的 Split面板
        /// </summary>
        /// <param name="split"></param>
        /// <returns></returns>
        public XIDESplitPanel FindParentPanel(XIDESplitControl split)
        {
            if (split == null) return null;

            var splits = this.GetListSplit();
            foreach (var split2 in splits)
            {
                if (split2.Panel1.Split == split) return split.Panel1;
                if (split2.Panel2.Split == split) return split.Panel2;
            }

            return null;
        }
        /// <summary>
        /// 查找指定 Group、SplitPanel、SplitControl 所属的 父级SplitControl
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public XIDESplitControl FindParentSplit(object obj)
        {
            if (obj == null) return null;
            var bak = obj;
            if (obj is XIDEGroup) obj = FindParentPanel((XIDEGroup)obj);
            if (obj is XIDESplitPanel) obj = ((XIDESplitPanel)obj).Owner;
            if (!(obj is XIDESplitControl)) throw new InvalidOperationException(string.Format("无法查找对象 [{0}] 所属的 XIDESplitControl", bak));

            var split = (XIDESplitControl)obj;
            var hash = this.GetHashSplitParent();
            return hash[split];
        }

        /// <summary>
        /// 中央文档区 相对 XIDEPanel 的位置
        /// </summary>
        /// <returns></returns>
        public Rectangle FindCenterRect()
        {
            var panel = this.FindCenterPanel();
            var rect = (panel != null) ? panel.Bounds : this.RectInner;
            return rect;
        }
        /// <summary>
        /// 中央文档区 相对 整个屏幕 的位置
        /// </summary>
        /// <returns></returns>
        public Rectangle FindCenterRectWindow()
        {
            var rect = this.FindCenterRect();
            return this.RectangleToScreen(rect);
        }
        /// <summary>
        /// 查找 中央文档区 所属的面板
        /// </summary>
        /// <returns></returns>
        public XIDESplitPanel FindCenterPanel()
        {
            var splits = this.GetListSplit();
            foreach (var split in splits)
            {
                if (split.Panel1.IsCenter) return split.Panel1;
                if (split.Panel2.IsCenter) return split.Panel2;
            }
            return null;
        }
        /// <summary>
        /// 查找 第一个 处于中央文档区 的分组集合
        /// </summary>
        /// <returns></returns>
        public XIDEGroup FindCenterGroup()
        {
            var list = FindListCenterGroup();
            return (list == null || list.Count <= 0) ? null : list[0];
        }
        /// <summary>
        /// 查找所有 处于中央文档区 的分组集合
        /// </summary>
        /// <returns></returns>
        public List<XIDEGroup> FindListCenterGroup()
        {
            var panel = this.FindCenterPanel();
            if (panel == null) return new List<XIDEGroup>();

            if (panel.Group != null) return new List<XIDEGroup> {panel.Group};
            if (panel.Split != null)
            {
                var list = new List<XIDEGroup>();
                EmitAction<XIDESplitControl> action = null;
                action = (split) =>
                {
                    if (split.Panel1.Group != null) list.Add(split.Panel1.Group);
                    if (split.Panel2.Group != null) list.Add(split.Panel2.Group);
                    if (split.Panel1.Split != null) action(split.Panel1.Split);
                    if (split.Panel2.Split != null) action(split.Panel2.Split);
                };
                action(panel.Split);
                return list;
            }
            return null;
        } 

        /// <summary>
        /// 获取 Split 之间的 父子关系, 返回的 Hash 中 Key是 子Split, Value是 父Split 
        /// </summary>
        /// <returns></returns>
        public Hash<XIDESplitControl, XIDESplitControl> GetHashSplitParent()
        {
            var splits = this.GetListSplit();
            var hashP = new Hash<XIDESplitControl, XIDESplitControl>();
            foreach (var split in splits)
            {
                var childS1 = split.Panel1.Split;
                var childS2 = split.Panel2.Split;
                if (childS1 != null) hashP[childS1] = split;
                if (childS2 != null) hashP[childS2] = split;
            }
            return hashP;
        }

        #endregion


        #region  分 割 拖 拽

        /// <summary>
        /// 内部字段
        /// </summary>
        protected SplitterForm m_DragSplitter;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Cursor m_BakCursor = null;


        /// <summary>
        /// 获取或设置当鼠标指针位于控件上时显示的光标。
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public override Cursor Cursor
        {
            get { return base.Cursor; }
            set { base.Cursor = value; }
        }
        /// <summary>
        /// 当前分割线 是否正在移动中 (即; 当前是否正在执行 分割线的拖拽)
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual bool IsSplitMoving
        {
            get { return m_DragSplitter != null && m_DragSplitter.IsSplitMoving; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual XIDESplitControl DragSplit
        {
            get { return m_DragSplitter == null ? null : (m_DragSplitter.Tag as XIDESplitControl); }
        }





        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseMove 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            var drapSplit = this.DragSplit;
            if (drapSplit != null && IsSplitMoving)
            {
                var cursor = (drapSplit.IsHorizontal ? Cursors.HSplit : Cursors.VSplit);
                SetCursor(cursor);
                DrawSplitter();
            }
            else
            {
                var splitM = FindSplitSplitter(e.Location);
                var cursor = splitM == null ? this.Cursor : (splitM.IsHorizontal ? Cursors.HSplit : Cursors.VSplit);
                this.SetCursor(cursor);
            }

            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseLeave 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            SetCursor(null);
            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseDown 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            var splitM = FindSplitSplitter(e.Location);
            if (splitM != null) { this.BeginSplitter(splitM); }

            this.Invalidate();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseUp 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            XIDESplitControl split = null;
            var info = EndSplitter(out split);
            DoSplitMoved(split, info);
        }

        /// <summary>
        /// 获取 指定光标位置 指向的分割条 的 分割控件
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        protected XIDESplitControl FindSplitSplitter(Point point)
        {
            var splits = this.GetListSplit();
            if (splits == null || splits.Count <= 0) return null;
            foreach (var split in splits) { if (split.SplitterRectangle.Contains(point)) { return split; } }
            return null;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="split">Type: XIDESplitControl</param>
        protected virtual void BeginSplitter(XIDESplitControl split)
        {
            if (split == null) return;
            var rectSplit2 = this.RectangleToScreen(split.SplitterRectangle);
            var rectRange2 = this.RectangleToScreen(split.RectSplitRange);
            var clip = Win32API.GetClipRegion(this);

            m_DragSplitter = SplitterForm.BeginSplitter(this.FindForm(), split.IsHorizontal, rectRange2, rectSplit2, clip);
            m_DragSplitter.Tag = split;
            m_DragSplitter.ShowSplitter(rectSplit2, clip);
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual void DrawSplitter()
        {
            if (m_DragSplitter != null) m_DragSplitter.ShowSplitter();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual SplitInfo EndSplitter(out XIDESplitControl split)
        {
            if (m_DragSplitter != null)
            {
                split = m_DragSplitter.Tag as XIDESplitControl;
                var result = m_DragSplitter.EndSplitter();
                if (m_DragSplitter != null) { m_DragSplitter.Tag = null; }
                m_DragSplitter = null;
                return result;
            }
            split = null;
            return SplitInfo.Empty;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual SplitInfo GetSplitInfo()
        {
            var info = (m_DragSplitter != null) ? m_DragSplitter.GetSplitInfo() : SplitInfo.Empty;
            var info2 = new SplitInfo(this.RectangleToClient(info.Start), this.RectangleToClient(info.End));
            return info2;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="split">Type: XIDESplitControl</param>
        /// <param name="info">Type: SplitInfo</param>
        protected void DoSplitMoved(XIDESplitControl split, SplitInfo info)
        {
            var diff = info.Diff;
            if (diff.X == 0 && diff.Y == 0) return;
            if (split == null) return;

            if (split.IsHorizontal) { split.SplitterDistance = split.SplitterDistance + diff.Y; }
            else { split.SplitterDistance = split.SplitterDistance + diff.X; }

            this.ResetLayout();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cursor">Type: System.Windows.Forms.Cursor</param>
        protected void SetCursor(System.Windows.Forms.Cursor cursor)
        {
            if (m_BakCursor == null) m_BakCursor = base.Cursor ?? Cursors.Default;
            var baseCursor = base.Cursor;
            if (baseCursor != null && baseCursor != cursor)
                base.Cursor = cursor ?? m_BakCursor;
        }

        #endregion




        #region  布 局 XML

        /// <summary>
        /// 获取 当前XIDEPanel 的 布局XML 字符串
        /// </summary>
        /// <param name="action">在 action 回调中, 可以给 Frame 节点手动添加 额外的属性, 比如: node["Id"] = frame.Id; </param>
        public string GetLayoutXml(EmitAction<LayoutNode, XIDEFrame> action)
        {
            #region  作废的代码

            //EmitFunc<List<string>, List<string>> func0 = null;
            //func0 = (List<string> list) =>
            //{
            //    var list2 = new List<string>();
            //    foreach (var item in list) { list2.Add("    " + item); }
            //    return list2;
            //};

            //EmitFunc<System.Windows.Forms.Control, List<string>> func1 = null;
            //func1 = (System.Windows.Forms.Control ctrl) =>
            //{
            //    if (ctrl == null) return null;

            //    var str = "";
            //    var left = "    ";

            //    var list = new List<string>();
            //    var split = ctrl as XIDESplitControl;
            //    var group = ctrl as XIDEGroup;
            //    var frame = ctrl as XIDEFrame;
            //    if (split != null)
            //    {
            //        var pan1 = split.Panel1;
            //        var pan2 = split.Panel2;
            //        var str1 = func0(func1(pan1.Control));
            //        var str2 = func0(func1(pan2.Control));
            //        str = ("Split :" + split.Text);
            //        if (str1 != null) { list.Add("P1 : "); list.AddRange(str1); }
            //        if (str2 != null) { list.Add("P2 : "); list.AddRange(str2); }
            //    }
            //    if (group != null)
            //    {
            //        str = ("Group :" + group.Text + " \t" + group.State);
            //        foreach (var page in group.ListPage)
            //        {
            //            var str1 = func1(page.Frame);
            //            if (str1 != null) { list.AddRange(str1); }
            //        }
            //    } 
            //    if (frame != null)
            //    {
            //        str = ("Frame :" + frame.Text);
            //    }


            //    var list2 = new List<string>();
            //    list2.Add(str);
            //    list2.AddRange(func0(list));
            //    return list2;
            //};

            //EmitFunc<System.Windows.Forms.Control.ControlCollection, int, List<string>> func2 = null;
            //func2 = (System.Windows.Forms.Control.ControlCollection ctrls, int level) =>
            //{
            //    var list = new List<string>();
            //    foreach (System.Windows.Forms.Control ctrl in ctrls)
            //    {
            //        var list2 = func1(ctrl);
            //        if (list2 != null && list2.Count >= 1) list.AddRange(list2);
            //    }

            //    list.RemoveAll(string.IsNullOrWhiteSpace);
            //    return list;
            //};

            //var lines = func2(panel.Controls, 0);
            //Console.WriteLine("----------------------------------");
            //Console.WriteLine(string.Join("\r\n", lines.ToArray()));

            #endregion


            var node = LayoutNode.FromIDEPanel(this, action);
            return node == null ? string.Empty : node.ToXml();
        }
        /// <summary>
        /// 通过指定的 布局XML 设置 当前XIDEPanel 的 布局
        /// </summary>
        /// <param name="xml">布局XML</param>
        /// <param name="func">在 func 回调中, 通过指定的 node 构建一个 Frame, 比如: return new MyFrame(node["Id"]); </param>
        public void SetLayoutXml(string xml, EmitFunc<LayoutNode, XIDEFrame> func)
        {
            if (Tools.IsNullOrWhiteSpace(xml) || func == null) return;

            var node = LayoutNode.FromXml(xml);
            if (node == null) return;

            var nodes = node.GetAllNodes();
            var frames = nodes.FindAll(x => x.Name == "Frame");
            if (frames.Count <= 0) return;

            //Console.WriteLine(nodes);
            var idePanel = this;


            //EmitFunc<LayoutNode, LayoutNode> FindP2 = (node2) =>
            //{
            //    #region  查找 Split 另外的 P

            //    var p1 = node2 == null ? null : node2.Parent;
            //    var pS = p1 == null ? null : p1.Parent;
            //    if (pS == null || pS.Name != "Split") return null;

            //    var p2 = pS.Nodes.Find(x => x != p1);
            //    if (p2 == null || p2.Nodes.Count <= 0) return null;
            //    if (p2.Nodes.Count >= 2) { /*throw new Exception("无法查找到 Split 的 另一个P元素"); */ return null; }

            //    return p2.Nodes[0];

            //    #endregion
            //};


            EmitAction<XIDESplitPanel, LayoutNode> Rebuild = null;
            Rebuild = (panel, node2) =>
            {
                if (node2 == null) return;
                if (node2.Name == "Split")
                {
                    #region  重建 Split

                    var IsVert = Tools.ToBoolean(node2["IsVert"]);
                    var Fixed = Tools.ToEnum<FixedPanel>(node2["Fixed"]);
                    var SplitDist = Tools.ToInt(node2["SplitDist"]);

                    var split = new XIDESplitControl(idePanel);
                    split.Bounds = new Rectangle(0, 0, 500, 500);
                    split.IsHorizontal = (!IsVert);
                    split.FixedPanel = Fixed;
                    split.FixedPanelSize = SplitDist;
                    if (panel != null) panel.SetChild(split);

                    var nodeP1 = node2.Nodes.Find(x => x.Name == "P1");
                    var nodeP2 = node2.Nodes.Find(x => x.Name == "P2");
                    var nodePC1 = (nodeP1 == null || nodeP1.Nodes.Count <= 0) ? null : nodeP1.Nodes[0];
                    var nodePC2 = (nodeP2 == null || nodeP2.Nodes.Count <= 0) ? null : nodeP2.Nodes[0];

                    var centerP1 = nodeP1 != null && Tools.ToBoolean(nodeP1["Center"], false);
                    var centerP2 = nodeP2 != null && Tools.ToBoolean(nodeP2["Center"], false);
                    if (centerP1) split.Panel1.IsCenter = true;
                    if (centerP2) split.Panel2.IsCenter = true;

                    Rebuild(split.Panel1, nodePC1);
                    Rebuild(split.Panel2, nodePC2);
                    split.FixedPanelSize = SplitDist;

                    #endregion
                }
                else if (node2.Name == "Group")
                {
                    #region  重建 Group

                    var active = Tools.ToInt(node2["Active"], -1);
                    var align = Tools.ToEnum<XIDEAlignment>(node2["Align"]);
                    var state = Tools.ToEnum<XIDEGroupState>(node2["State"]);
                    var group = new XIDEGroup(idePanel, align);

                    var nodes2 = node2.Nodes;
                    for (int i = nodes2.Count - 1; i >= 0; i--) //下面的 Group.DoDock(*) 函数 会导致后加载的Frame 摆在首位, 所以这里需要 倒序加载
                    {
                        var node3 = nodes2[i];
                        if (node3.Name != "Frame") continue;
                        var frame = func(node3);
                        if (frame == null) continue;
                        frame.LoadLayoutNode(node3);

                        var groupF = idePanel.FindGroup(frame);
                        if (groupF == null) { group.DoDock(frame, XIDEAlignment.Center); }
                        else { group.DoDock(groupF, XIDEAlignment.Center); }
                    }

                    if (group.ListPage.Count <= 0) { group.Dispose(); idePanel.UnRegGroup(group); }
                    else
                    {
                        //恢复折叠状态
                        if (state == XIDEGroupState.Collapse) group.DoCollapse();

                        //设置激活面板
                        if (active >= 1)
                        {
                            var list = group.ListPage.FindAll(x => !(x.Frame is XIDETempFrame));
                            var activePage = list.Count > active ? list[active] : null;
                            if (activePage != null && list.Count >= 2) group.SetActivePage(activePage);
                        }
                    }

                    if (panel != null) panel.SetChild(group);

                    #endregion
                }
            };

            //执行布局恢复
            idePanel.TransLayout(() =>
            {
                idePanel.m_ListGroup.Clear();
                idePanel.m_ListSplitControl.Clear();
                Rebuild(null, node);
            });

        }


        /// <summary>
        /// XIDEPanel 的 布局节点
        /// </summary>
        public class LayoutNode
        {
            public LayoutNode(string name)
            {
                if (Tools.IsNullOrWhiteSpace(name)) throw new ArgumentNullException("name");
                this.Name = name;
            }



            protected string m_Name = string.Empty;
            protected LayoutNode m_Parent = null;
            protected HashKeyValue m_Hash = null;
            protected LayoutNodeList m_Nodes = null;


            public string Name
            {
                get { return m_Name; }
                set
                {
                    m_Name = (value + "").Trim();
                    if (string.Equals(m_Name, "Split", StringComparison.CurrentCultureIgnoreCase)) m_Name = "Split";
                    else if (string.Equals(m_Name, "Group", StringComparison.CurrentCultureIgnoreCase)) m_Name = "Group";
                    else if (string.Equals(m_Name, "Frame", StringComparison.CurrentCultureIgnoreCase)) m_Name = "Frame";
                    else if (string.Equals(m_Name, "Center", StringComparison.CurrentCultureIgnoreCase)) m_Name = "Center";
                    else if (string.Equals(m_Name, "P1", StringComparison.CurrentCultureIgnoreCase)) m_Name = "P1";
                    else if (string.Equals(m_Name, "P2", StringComparison.CurrentCultureIgnoreCase)) m_Name = "P2";
                }
            }
            public LayoutNode Parent
            {
                get { return m_Parent; }
                internal set { m_Parent = value; }
            }
            public string this[string key]
            {
                get
                {
                    if (m_Hash == null || Tools.IsNullOrWhiteSpace(key)) return string.Empty;
                    key = key.Replace("&", "").Replace("'", "").Replace("\"", "").Replace("<", "").Replace(">", "");
                    var value = m_Hash[key];
                    return value;
                }
                set
                {
                    if (Tools.IsNullOrWhiteSpace(key)) return;
                    if (m_Hash == null) m_Hash = new HashKeyValue();
                    key = key.Replace("&", "").Replace("'", "").Replace("\"", "").Replace("<", "").Replace(">", "");
                    m_Hash[key] = (value + "").Trim();
                }
            }
            public LayoutNodeList Nodes
            {
                get
                {
                    if (m_Nodes == null) m_Nodes = new LayoutNodeList(this);
                    return m_Nodes;
                }
                set
                {
                    if (m_Nodes == value) return;
                    if (m_Nodes == null) m_Nodes = new LayoutNodeList(this);
                    else m_Nodes.Clear();
                    if (value != null && value.Count >= 1) m_Nodes.AddRange(value);
                }
            }



            public List<LayoutNode> GetAllNodes()
            {
                var list = new List<LayoutNode>();
                list.Add(this);

                if (m_Nodes != null && m_Nodes.Count >= 1)
                {
                    foreach (var node in m_Nodes)
                    {
                        if (node.Nodes.Count >= 1) { var list2 = node.GetAllNodes(); list.AddRange(list2); }
                        else { list.Add(node); }
                    }
                }

                return list;
            }





            public string ToXml()
            {
                return ToXml(0);
            }
            public string ToXml(int level)
            {
                var left = new string(' ', (level * 4));

                var list = new List<string>();
                if (m_Hash != null) { foreach (var pair in m_Hash) { list.Add(string.Format("{0}=\"{1}\" ", pair.Key, EncodeXml(pair.Value))); } }
                var str = left + string.Format("<{0}{1}", this.Name, (list.Count <= 0 ? "" : " " + string.Join(" ", list.ToArray())));

                var nodes = this.Nodes;
                if (nodes == null || nodes.Count <= 0) { str = str + "/>"; }
                else
                {
                    str = str + ">";
                    foreach (var node2 in nodes)
                    {
                        var str2 = node2.ToXml(level + 1);
                        str = str + "\r\n" + str2;
                    }
                    str = str + string.Format("\r\n{0}</{1}>", left, this.Name);
                }
                return str;
            }

            public static LayoutNode FromXml(string xml)
            {
                if (Tools.IsNullOrWhiteSpace(xml)) return null;

                var xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xml);

                var nodes = xmlDoc.ChildNodes;
                var root = nodes[0];
                var node = FromXmlNode(root);
                return node;
            }
            public static LayoutNode FromXmlNode(XmlNode xmlNode)
            {
                if (xmlNode == null) return null;

                var name = xmlNode.Name;
                LayoutNode node = null;
                if (string.Equals(name, "Split", StringComparison.CurrentCultureIgnoreCase))
                {
                    node = new LayoutNode("Split");
                    var nodeP1 = new LayoutNode("P1");
                    var nodeP2 = new LayoutNode("P2");
                    node.Nodes.Add(nodeP1);
                    node.Nodes.Add(nodeP2);

                    var xmlNodeP1 = xmlNode.SelectSingleNode("P1");
                    var xmlNodeP2 = xmlNode.SelectSingleNode("P2");
                    SetLayoutNodeAttrs(nodeP1, xmlNodeP1);
                    SetLayoutNodeAttrs(nodeP2, xmlNodeP2);

                    var xmlNodePC1 = (xmlNodeP1 == null || xmlNodeP1.ChildNodes.Count <= 0) ? null : xmlNodeP1.ChildNodes[0];
                    var xmlNodePC2 = (xmlNodeP2 == null || xmlNodeP2.ChildNodes.Count <= 0) ? null : xmlNodeP2.ChildNodes[0];


                    var nodePC1 = FromXmlNode(xmlNodePC1);
                    var nodePC2 = FromXmlNode(xmlNodePC2);
                    if (nodePC1 != null) nodeP1.Nodes.Add(nodePC1);
                    if (nodePC2 != null) nodeP2.Nodes.Add(nodePC2);
                }
                else if (string.Equals(name, "Group", StringComparison.CurrentCultureIgnoreCase))
                {
                    node = new LayoutNode("Group");
                    foreach (XmlNode xmlNodeF in xmlNode.ChildNodes)
                    {
                        var nodeF = FromXmlNode(xmlNodeF);
                        if (nodeF != null) node.Nodes.Add(nodeF);
                    }
                }
                else if (string.Equals(name, "Frame", StringComparison.CurrentCultureIgnoreCase))
                {
                    node = new LayoutNode("Frame");
                }

                SetLayoutNodeAttrs(node, xmlNode);

                return node;
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="panel"></param>
            /// <param name="action"></param>
            /// <returns></returns>
            public static LayoutNode FromIDEPanel(XIDEPanel panel, EmitAction<LayoutNode, XIDEFrame> action)
            {
                if (panel == null || panel.Controls.Count <= 0) return null;

                panel.TryDestroySplits();
                //panel.ResetLayout(); //如果执行了 ResetLayout() 就会触发 布局改变事件, 布局改变事件又会触发本函数
                var groups = panel.GetListGroup();
                if (groups == null || groups.Count <= 0) return null;

                var splitOut = panel.FindOuterSplit();
                if (splitOut != null) return FromControl(splitOut, action);

                var groupOut = panel.FindOuterGroup();
                if (groupOut != null) return FromControl(groupOut, action);

                return null;
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="ctrl"></param>
            /// <param name="action"></param>
            /// <returns></returns>
            public static LayoutNode FromControl(object ctrl, EmitAction<LayoutNode, XIDEFrame> action)
            {
                var split = ctrl as XIDESplitControl;
                var group = ctrl as XIDEGroup;
                var frame = ctrl as XIDEFrame;

                LayoutNode node = null;
                if (split != null)
                {
                    node = new LayoutNode("Split");
                    node["Fixed"] = split.FixedPanel + "";
                    node["IsVert"] = (!split.IsHorizontal) + "";
                    node["SplitDist"] = split.FixedPanelSize + "";

                    var nodeP1 = new LayoutNode("P1");
                    var nodeP2 = new LayoutNode("P2");
                    node.Nodes.Add(nodeP1);
                    node.Nodes.Add(nodeP2);
                    if (split.Panel1.IsCenter) nodeP1["Center"] = (true + "");
                    if (split.Panel2.IsCenter) nodeP2["Center"] = (true + "");

                    var nodePC1 = FromControl(split.Panel1.Child, action);
                    var nodePC2 = FromControl(split.Panel2.Child, action);
                    if (nodePC1 != null) nodeP1.Nodes.Add(nodePC1);
                    if (nodePC2 != null) nodeP2.Nodes.Add(nodePC2);
                }
                else if (group != null)
                {
                    var state = group.State;
                    if (state != XIDEGroupState.Dispose)
                    {
                        if (state == XIDEGroupState.Float) state = XIDEGroupState.Expand;
                        else if (state == XIDEGroupState.Popup) state = XIDEGroupState.Collapse;

                        var activePage = group.ActivePage;
                        var activeIndex = (activePage != null && group.ListPage.Count >= 1) ? group.ListPage.IndexOf(activePage) : -1;

                        node = new LayoutNode("Group");
                        node["State"] = state + "";
                        node["Align"] = group.Alignment + "";
                        node["Active"] = activeIndex + "";
                        foreach (var page in group.ListPage)
                        {
                            var nodeF = FromControl(page.Frame, action);
                            if (nodeF != null) node.Nodes.Add(nodeF);
                        }
                    }
                }
                else if (frame != null)
                {
                    node = new LayoutNode("Frame");
                    node["Type"] = frame.GetType().FullName;
                    node["Text"] = frame.Text;
                    frame.SaveLayoutNode(node);
                    if (action != null) action(node, frame);
                }

                return node;
            }

            /// <summary>
            /// 将属性 恢复到 LayoutNode 中
            /// </summary>
            /// <param name="node"></param>
            /// <param name="xmlNode"></param>
            public static void SetLayoutNodeAttrs(LayoutNode node, XmlNode xmlNode)
            {
                if (node != null && xmlNode != null && xmlNode.Attributes != null && xmlNode.Attributes.Count >= 1)
                {
                    foreach (XmlAttribute attr in xmlNode.Attributes) { node[attr.Name] = attr.Value; }
                }
            }


            private static string EncodeXml(string str)
            {
                if (Tools.IsNullOrWhiteSpace(str)) return str + "";

                //"	&quot;
                //'	&apos;
                //<	&lt;
                //>	&gt;
                //&	&amp;

                var str2 = str.Replace("&", "&amp;")
                    .Replace(">", "&gt;")
                    .Replace("<", "&lt;")
                    .Replace("'", "&apos;")
                    .Replace("\"", "&quot;");
                return str2;
            }
            public override string ToString()
            {
                var list = new List<string>();
                if (m_Hash != null) { foreach (var pair in m_Hash) { list.Add(string.Format("{0}='{1}' ", pair.Key, pair.Value)); } }
                return this.Name + " " + string.Join(" ", list.ToArray());
            }


        }
        /// <summary>
        /// XIDEPanel 的 布局节点集合
        /// </summary>
        public class LayoutNodeList : List<LayoutNode>
        {
            public LayoutNodeList(LayoutNode owner)
            {
                m_Owner = owner;
            }

            protected LayoutNode m_Owner = null;
            public LayoutNode Owner
            {
                get { return m_Owner; }
            }

            public new void Add(LayoutNode node)
            {
                base.Add(node);
                node.Parent = Owner;
            }
            public new void Insert(int index, LayoutNode node)
            {
                base.Insert(index, node);
                node.Parent = Owner;
            }
            public new void Remove(LayoutNode node)
            {
                node.Parent = null;
                base.Remove(node);
            }
            public new void RemoveAt(int index)
            {
                var node = base[index];
                if (node != null) { node.Parent = null; }
                base.RemoveAt(index);
            }
            public new void RemoveAll(Predicate<LayoutNode> match)
            {
                var nodes = base.FindAll(match);
                foreach (var node in nodes) { node.Parent = null; }
                base.RemoveAll(match);
            }
            public new void Clear()
            {
                foreach (var node in this) { node.Parent = null; }
                base.Clear();
            }
        }


        #endregion

    }
}
